fix: keep completion subcommand order deterministic in help output#2374
fix: keep completion subcommand order deterministic in help output#2374suzuki-shunsuke wants to merge 2 commits into
Conversation
The completion command exposes each shell (bash, zsh, fish, pwsh) as a subcommand. These were generated by ranging over the shellCompletions map, whose iteration order Go randomizes per process. As a result the order of subcommands in `completion --help` changed between runs, which broke downstream projects that generate and commit documentation from --help output. Iterate over an explicitly ordered slice of shell names so the listing is stable (bash, zsh, fish, pwsh) on every run. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| // subcommands appear in help output. Iterating shellCompletions directly | ||
| // would use Go's randomized map order, making the listing nondeterministic. | ||
| // Keep this in sync with shellCompletions. | ||
| completionShells = []string{"bash", "zsh", "fish", "pwsh"} |
There was a problem hiding this comment.
Is it possible to get sorted list instead of maintaining hardcoded indexes?
There was a problem hiding this comment.
In case of the dictionary order, the order is changed.
- bash
- fish
- pwsh
- zsh
Is that okay?
I think the current order is more natural.
- bash
- zsh
- fish
- pwsh
https://cli.urfave.org/v3/examples/completions/shell-completions/
Review: PR #2374 — Deterministic completion subcommand orderVerdict: Clean fix. No bugs. The root cause is correctly identified (Go map iteration randomization). The fix is minimal and correct: a Minor observations (none blocking):
Ready to merge. |
What type of PR is this?
What this PR does / why we need it:
The
completioncommand exposes each shell as its own subcommand (bash,zsh,fish,pwsh), introduced in #2279 (released in v3.9.1). The subcommands were generated by ranging over theshellCompletionsmap inbuildCompletionCommand:Go randomizes map iteration order per process, so the order of these subcommands — and therefore the
COMMANDS:section ofcompletion --help— changed between runs. This breaks downstream projects that generate documentation from--helpoutput and commit it via CI: the generated docs flip-flop depending on which run produced them, creating spurious diffs and noise commits. Real-world impact: suzuki-shunsuke/ghtkn#454Changes:
completion.go: addcompletionShells = []string{"bash", "zsh", "fish", "pwsh"}, an explicitly ordered list of the supported shells, and iterate it (looking the renderer up inshellCompletions) instead of ranging over the map. The map stays as the renderer registry; the slice fixes the display order. The order is now deterministic on every run.completion_test.go: addTestCompletionSubcommandOrder, which asserts the subcommand order is alwaysbash, zsh, fish, pwshand that every shell inshellCompletionsis also present incompletionShells(so the two cannot silently drift).TestCompletionShellRenderErrorandTestCompletionShellWriteErrorinject a custom shell intoshellCompletions; they now also register it incompletionShells(with restore) so the injected shell still becomes a subcommand.Which issue(s) this PR fixes:
Fixes #2373
Special notes for your reviewer:
The display order is fixed to
bash, zsh, fish, pwsh. If you would prefer alphabetical order instead, that is a one-line change tocompletionShells.Testing
go test ./...passes.go testinvocations (separate processes), where the subcommand order previously varied.Release Notes